﻿using System;
using System.Collections.Generic;

namespace ForgeCraft
{
    public abstract class Window
    {
        private static byte _NextID = 2;
        protected List<Player> _Viewers;

        public byte ID;
        public byte Type;
        public string Title;
        public string allowedPlayers;
        public string ownerName;
        public DateTime createdDate;
        public bool isPublic;
        public string additional;

        public InventoryItem[] slots { get; protected set; }

        protected Window(byte type, string title)
        {
            _Viewers = new List<Player>();
            ID = _NextID;
            createdDate = DateTime.UtcNow;
            isPublic = true;
            allowedPlayers = "";
            ownerName = "";
            additional = "";

            if (++_NextID > 125) _NextID = 2;
            Type = type;
            Title = title;
        }

        virtual public void Open(Player player)
        {
            _Viewers.Add(player);

            player.OpenWindow(this);
            player.FillWindow(this);
        }

        virtual public void Save(Player player)
        {
            player.info.InventorySave(player);
        }

        virtual public void Remove(World world)
        {
            //TODO: Log this removal?
        }

        virtual public void Close(Player player)
        {
            _Viewers.Remove(player);
            //TODO: This probably needs to be saved somewhere.
            /*if (_Viewers.Count == 0)
            {
                Remove(this);
            }*/
        }

        public abstract bool Click(Player p, short slot, byte type, InventoryItem item);

        public void SetSlot(short slot, InventoryItem item)
        {
            //TODO: Neaten/sort this quick fix to stop the client crashing with nil item;
            if (item.Type == 0)
            {
                item.Clear();
            }

            slots[slot] = item;
            foreach (Player player in _Viewers)
            {
                //Logger.Log("Window.cs->SetSlot: " + this.ID + ":" + this.Title + " S:" + slot + " I:" + item.Type + ":" + item.Count, LogType.Testing);
                player.WindowSetSlot(this, slot, item);
                
            }
        }

        virtual public InventoryItem PopItem(InventoryItem item, byte i = 1)
        {
            //TODO: This probably has an issue with sticks being 4. (Yeah, there is, but it ain't too serious)
            //..But does it? This removes an item, so why would 4 be an issue??? 
            if (item.Type > 0)
            {
                if (item.Count == i)
                {
                    item.Clear();
                }
                else
                {
                    item.Count -= i;
                }
            }

            return item;
        }

        virtual public string GetInventory()
        {
            string itemlist = "";

            for (int i = 0; i < this.slots.Length; i++)
            {
                if (this.slots[i].Type > 0)
                {
                    itemlist += this.slots[i].Type + ":" + this.slots[i].Count + ", ";
                }
            }

            return itemlist;
        }

        virtual public void UpdateViewers(short updateType)
        {
            foreach (Player p in _Viewers)
            {
                if (this.Type == 2)
                {
                    Logger.Log("Sending Furnace {0} update to {1}.", LogType.Testing, this.ID, p.name);

                    p.Send(PacketWriter.MakeUpdateProgressBar(this, updateType));
                }
            }
        }

        virtual public Pair<bool, InventoryItem> TryAddItem(short slot, InventoryItem item)
        {
            if (slots[slot].Type == -1)
            {
                SetSlot(slot, item);
                item.Clear();
                return new Pair<bool, InventoryItem>(true, item);
            }
            else if (slots[slot].Type == item.Type)
            {
                if (slots[slot].Type < 255)
                {
                    if (slots[slot].Damage != item.Damage)
                    {
                        return new Pair<bool, InventoryItem>(false, item);
                    }
                }

                if (slots[slot].Count + item.Count <= 64)
                {
                    slots[slot].Count += item.Count;
                    SetSlot(slot, slots[slot]);
                    item.Clear();
                    return new Pair<bool, InventoryItem>(true, item);
                }
                else
                {
                    // Dont think extra logic required, it'll always have a count left.
                    while (slots[slot].Count < 64 && item.Count > 0)
                    {
                        slots[slot].Count++;
                        item.Count--;
                    }
                    SetSlot(slot, slots[slot]);

                    return new Pair<bool, InventoryItem>(false, item);
                }

            }
            return new Pair<bool, InventoryItem>(false, item); ;
        }
    }
}
